package com.siashan.toolkit.core.util;

import java.util.Random;

/**
 * 邀请码生成器，算法原理：<br/> *
 * 1) 获取id: 1127738 <br/> *
 * 2) 使用自定义进制转为：gpm6 <br/> *
 * 3) 转为字符串，并在后面加'o'字符：gpm6o <br/> *
 * 4）在后面随机产生若干个随机数字字符：gpm6o7 <br/> *
 * 转为自定义进制后就不会出现o这个字符，然后在后面加个'o'，这样就能确定唯一性。最后在后面产生一些随机字符进行补全。<br/> *
 *
 *
 * 指定生成的随机码长度，在ID超过一定数值时，会超过指定的随机码长度，在使用该工具时，需要根据自身数据阈值量酌情判断
 */
public class ShareCodeUtil {
    public static void main(String[] args) {
//        String serialCode = ShareCodeUtil.toSerialCode(1654373761653911553L);
//        String serialCode = ShareCodeUtil.toSerialCode(1654373762L);
//        System.out.println(serialCode);
//        System.out.println(ShareCodeUtil.codeToId("hvsy6888355v"));



        String serialCode = ShareCodeUtil.toSerialCode(1654373762L,8);
        System.out.println(serialCode);
        System.out.println(ShareCodeUtil.codeToId("wxxq7tzo"));
    }

    /**
     * 自定义进制(0,1没有加入,容易与o,l混淆)
     */
    private static final char[] r = new char[]{'q', 'w', 'e', '8', 'a', 's', '2', 'd', 'z', 'x', '9', 'c', '7', 'p',
            '5', 'i', 'k', '3', 'm', 'j', 'u', 'f', 'r', '4', 'v', 'y', 'l', 't', 'n', '6', 'b', 'g', 'h'};
    /**
     * (不能与自定义进制有重复)
     */
    private static final char b = 'o';
    /**
     * 进制长度
     */
    private static final int binLen = r.length;
    /**
     * 生成序列最小长度
     */
    private static final int slen = 6;

    /**
     * 根据ID生成六位随机码
     *
     * @apiNote 当ID 超过 10亿的话，生成的邀请码会大于6位
     *
     * @param id ID
     * @return 邀请码
     */
    public static String toSerialCode(long id) {
        char[] buf = new char[32];
        int charPos = 32;
        while ((id / binLen) > 0) {
            int ind = (int) (id % binLen);
            buf[--charPos] = r[ind];
            id /= binLen;
        }
        buf[--charPos] = r[(int) (id % binLen)];
        String str = new String(buf, charPos, (32 - charPos));
        // 不够长度的自动随机补全
        if (str.length() < slen) {
            StringBuilder sb = new StringBuilder();
            sb.append(b);
            Random rnd = new Random();
            for (int i = 1; i < slen - str.length(); i++) {
                sb.append(r[rnd.nextInt(binLen)]);
            }
            str += sb.toString();
        }
        return str;
    }


    /**
     * 根据ID生成指定位数随机码
     *
     * @param id ID
     * @return 邀请码
     */
    public static String toSerialCode(long id,int slen) {
        char[] buf = new char[32];
        int charPos = 32;
        while ((id / binLen) > 0) {
            int ind = (int) (id % binLen);
            buf[--charPos] = r[ind];
            id /= binLen;
        }
        buf[--charPos] = r[(int) (id % binLen)];
        String str = new String(buf, charPos, (32 - charPos));
        // 不够长度的自动随机补全
        if (str.length() < slen) {
            StringBuilder sb = new StringBuilder();
            sb.append(b);
            Random rnd = new Random();
            for (int i = 1; i < slen - str.length(); i++) {
                sb.append(r[rnd.nextInt(binLen)]);
            }
            str += sb.toString();
        }
        return str;
    }

    /**
     * 邀请码转ID
     *
     * @param code 邀请码
     * @return ID
     */
    public static long codeToId(String code) {
        char chs[] = code.toCharArray();
        long res = 0L;
        for (int i = 0; i < chs.length; i++) {
            int ind = 0;
            for (int j = 0; j < binLen; j++) {
                if (chs[i] == r[j]) {
                    ind = j;
                    break;
                }
            }
            if (chs[i] == b) {
                break;
            }
            if (i > 0) {
                res = res * binLen + ind;
            } else {
                res = ind;
            }
        }
        return res;
    }
}